package com.chenxin.transaction.service.impl;

import com.chenxin.transaction.dao.AccountInfoDao;
import com.chenxin.transaction.feign.LisiFeign;
import com.chenxin.transaction.service.TccAccountInfoService;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hmily.annotation.Hmily;
import org.dromara.hmily.core.concurrent.threadlocal.HmilyTransactionContextLocal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
public class TccZhangsanAccountInfoServiceImpl implements TccAccountInfoService {

    @Autowired
    private AccountInfoDao accountInfoDao;

    @Autowired
    private LisiFeign lisiFeign;

    @Override
    @Transactional
    //只要标记@Hmily就是try方法，在注解中指定confirm、cancel两个方法的名字
    @Hmily(confirmMethod="confirm",cancelMethod="rollback")
    public void updateAccountBalance(String accountNo, Double amount) {

        //事务id
        String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();
        log.info(" 张三发起转账的事务id是：{}", transId);

        int existTry = accountInfoDao.isExistTry(transId);

        //try的幂等校验
        if (existTry > 0) {
            log.info("张三已经执行了try，无需重复执行，事务id是：{}", transId);
            return;
        }
        //try的悬挂处理：有可能因为网络发生拥塞导致try执行了，但是延时，延时过程中，rollback执行了
        if (accountInfoDao.isExistCancel(transId) > 0 || accountInfoDao.isExistConfirm(transId) > 0) {
            log.info("张三已经执行了confirm或者cancel，出现悬挂，无需重复执行，事务id是：{}", transId);
            return;
        }
        //真正从账户扣减
        if (accountInfoDao.subtractAccountBalance(accountNo, amount) <= 0) {
            throw new RuntimeException("张三 try扣减金额失败，事务id是：{}" + transId);
        }

        //执行扣减金额成功后插入try记录，用于幂等性校验
        accountInfoDao.addTry(transId);

//        //远程调用李四的服务进行转账
//        if (!lisiFeign.transfer(amount)) {
//            throw new RuntimeException("张三调用李四口转账异常，事务id是：{}" + transId);
//        }

        if (amount == 2) {
            throw new RuntimeException("人为制造异常，事务id是：{}" + transId);
        }

        log.info("张三转账执行完成！！事务id是：{}", transId);
    }

    /**
     * confirm方法
     *
     * @param accountNo
     * @param amount
     */
    @Transactional
    public void confirm(String accountNo, Double amount) {
        //获取全局事务id
        String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();
        log.info("张三 confirm begin 开始执行...xid:{},accountNo:{},amount:{}", transId, accountNo, amount);
    }

    /**
     * 转账失败的回滚操作
     *
     * @param accountNo
     * @param amount
     */
    @Transactional
    public void rollback(String accountNo, Double amount) {
        //获取全局事务的id
        String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();
        log.info("张三 rollback begin 开始执行...xid:{}", transId);
        //cancel幂等校验
        if (accountInfoDao.isExistCancel(transId) > 0) {
            log.info("bank1 cancel 已经执行，无需重复执行,xid:{}", transId);
            return;
        }
        //cancel空回滚处理，如果try没有执行，cancel不允许执行
        if (accountInfoDao.isExistTry(transId) <= 0) {
            log.info("bank1 空回滚处理，try没有执行，不允许cancel执行,xid:{}", transId);
            return;
        }
        //	增加可用余额
        accountInfoDao.addAccountBalance(accountNo, amount);
        //插入一条cancel的执行记录
        accountInfoDao.addCancel(transId);
        log.info("bank1 cancel end 结束执行...xid:{}", transId);
    }
}
